﻿#define _CRT_SECURE_NO_WARNINGS 1

#define NDEBUG 
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>

int ADD(int n)
{
	if (n == 1)
	{
		return 1;
	}
	return ADD(n) * ADD(n - 1);
}

int main()
{
	
}

////malloc 定义一个数组 跟另一个数组 长度相同;
////int ans = malloc(numsSize*sizeof(int));
//
//void main()
//{
//	char str[2];
//	scanf("%s", str); 
//	printf("%c,%c\n", str[0], str[1]);
//}

//int main() 
//{
//    int a, b;
//    while (scanf("%d %d", &a, &b) != EOF) 
//    {
//        if (b <= 12)
//        {
//            if ((a % 4 == 0 && a % 100 != 0) || a % 400 == 0)
//            {
//                if (b == 2)
//                {
//                    printf("%d\n", 29);
//                        
//                }
//          
//            }
//            else
//            {
//                if (b == 2)
//                {
//                    printf("%d\n", 28);
//                }
//            }
//            switch (b)
//            {
//            case 1:
//            case 3:
//            case 5:
//            case 7:
//            case 8:
//            case 10:
//            case 12:
//                printf("%d\n", 31);
//                break;
//            case 4:
//            case 6:
//            case 9:
//            case 11:
//                printf("%d\n", 30);
//                break;
//            }
//        }
//    }
//    return 0;
//}

//int main()
//{
//	int arr[] = { 1,2,3,4,5,1,2,3,4,6 };
//	int i = 0;
//	int j = 0;
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	for (i = 0; i < sz; i++)
//	{
//		int c = 1;
//		for (j = 0; j < sz; j++)
//		{
//			if (arr[i] == arr[j] && i != j)
//			{
//				c = 0;
//				break;
//			}
//		}
//		if (c == 1)
//		{
//			printf("%d ", arr[i]);
//		}
//	}
//	return 0;
//}

//int main()
//{
//	int a[4] = { 1, 2, 3, 4 };
//	int* ptr1 = (int*)(&a + 1);
//	int* ptr2 = (int*)((int)a + 1);
//	printf("%x,%x", ptr1[-1], *ptr2);// 4 
//	return 0;
//}


//int main()
//{
//	char* c[] = { "ENTER","NEW","POINT","FIRST" };
//	char** cp[] = { c + 3,c + 2,c + 1,c }; 						
//
//	//"FIRST" "POINT" "NEW" "ENTER"
//	char*** cpp = cp;//"FIRST"
//	printf("%s\n", **++cpp);// "POINT"
//	printf("%s\n", *-- * ++cpp + 3);//*++cpp ==*(c+1)   -- *(c+1)==*c    *（c+3）== ER 
//	//char** cp[] = { c + 3,c + 2,c,c };
//	//*cpp==第三个的c的地址；                             		
//	printf("%s\n", *cpp[-2] + 3);// cpp[-2] ==  *(cpp-2) == "FIRST" **(cpp-2)+3 ==ST
//	//*cpp==第三个的c的地址；
//	printf("%s\n", cpp[-1][-1] + 1);//  cpp[-1][-1]=="NEW"中的N cpp[-1][-1]+1==EW
//	return 0;
//}


//int main()
//{
//	char* a[] = { "work","at","alibaba" };
//	char** pa = a;
//	pa++;
//	printf("%s\n", *pa);
//	return 0;
//}

//int main()
//{
//	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
//	int* ptr1 = (int*)(&aa + 1);//跳过整个数组
//	int* ptr2 = (int*)(*(aa + 1));//跳过一行
//	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));// 10 5
//	return 0;
//}



////假设环境是x86环境，程序输出的结果是啥？
//#include <stdio.h>
//int main()
//{
//	int a[5][5];
//	int(*p)[4];
//	p = a;
//	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//  FFFFFFFC -4
//	return 0;                //-4                 //-4
//}


//int main()
//{
//	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
//	//逗号表达式只取最后一位数
//	// 1 3
//	// 5 0
//	// 0 0
//	int* p;
//	p = a[0];
//	printf("%d", p[0]);
//	return 0;
//}


////在X86环境下
////假设结构体的⼤⼩是20个字节
////程序输出的结构是啥？
////指针运算 加减整数
//struct Test
//{
//	int Num;
//	char* pcName;
//	short sDate;
//	char cha[2];
//	short sBa[4];
//}*p = (struct Test*)0x100000;
//int main()
//{
//	printf("%p\n", p + 0x1);//+1是跳过一个结构体  结构体的⼤⼩是20个字节 +20 //0x100014
//	printf("%p\n", (unsigned long)p + 0x1);//(unsigned long)是强制转换为无符号长整形 +1 //0x100001
//	printf("%p\n", (unsigned int*)p + 0x1);//(unsigned int*)是强制转换为整形指针 +4 //0x100004
//	return 0;
//}


//int main()
//{
//	char arr[] = "abcdef";
//	printf("%d\n", sizeof(arr));//7
//	printf("%d\n", sizeof(arr + 0));//4 地址
//	printf("%d\n", sizeof(*arr));//1 首元素
//	printf("%d\n", sizeof(arr[1]));//1 第二个元素
//	printf("%d\n", sizeof(&arr));//4 
//	printf("%d\n", sizeof(&arr + 1));//4
//	printf("%d\n", sizeof(&arr[0] + 1));//4
//	return 0;
//}

//int main()
//{
//	char arr[] = { 'a','b','c','d','e','f'};
//	printf("%d\n", strlen(arr));//随机
//	printf("%d\n", strlen(arr + 0));//随机 地址
//	printf("%d\n", strlen(*arr));//*arr->'a'--97 //非法访问
//	printf("%d\n", strlen(arr[1]));//*arr->'b'--98 //非法访问
//	printf("%d\n", strlen(&arr));//随机 地址
//	printf("%d\n", strlen(&arr + 1));//随机 地址
//	printf("%d\n", strlen(&arr[0] + 1));//随机 地址
//}

//int main()
//{
//	char arr[] = { 'a','b','c','d','e','f' };
//printf("%d\n", sizeof(arr));//6
//printf("%d\n", sizeof(arr + 0));//地址 是4/8个字节
//printf("%d\n", sizeof(*arr));//1
//printf("%d\n", sizeof(arr[1]));//1
//printf("%d\n", sizeof(&arr));//4
////地址是4/8个字节
//printf("%d\n", sizeof(&arr + 1));//4 地址
//printf("%d\n", sizeof(&arr[0] + 1));//4 地址
//	return 0;
//}

//int main()
//{
//	int a[] = { 1,2,3,4 };
//	printf("%d\n", sizeof(a));//16
//	printf("%d\n", sizeof(a + 0));//4
//	printf("%d\n", sizeof(*a));//4
//	printf("%d\n", sizeof(a + 1));//4
//	printf("%d\n", sizeof(a[1]));//4
//	printf("%d\n", sizeof(&a));//4
//	&a是取地址 取地址是4/8个字节
//	printf("%d\n", sizeof(*&a));//16
//
//}

//struct Stu
//{
//	char name[100];//名字
//	int age;//年龄
//};
//
//int main()
//{
//
//	struct Stu s[] = {"zhangsan",10};
//	struct Stu* p = &s;
//	printf("%s %d", (*p).name, (*p).age);
//	printf("%s %d", p->name, p->age);
//}

////void qsort(void* base,// base 是指向 待排序数据的第一个元素（起始地址） 
////	size_t num,// 待排序的元素个数
////	size_t size,//待排序的数组元素大小，单位字节
////	int(*compar)(const void*, const void*)//compar 是一个函数指针 指向的函数能比较2个元素
////);
//
////qsort有四个参数
////qsort 是快速排序
// //冒泡排序是 慢速排序
// 
////能够比较 e1 e2指向的元素 并且会返回值
////int cmp_int(const void* e1, const void* e2)//回调函数
////{	//void* 类型是无法直接解引用的 得强制转换类型才能解引用
////	return *(int*)e1 - *(int*)e2;
////	
////}
////
////void test()
////{
////	int arr[] = { 1,2,5,7,8,9,6,3,4,10 };
////	int sz = sizeof(arr) / sizeof(arr[0]);
////	for (int i = 0; i < sz; i++)
////	{
////		printf("%d ", arr[i]);
////	}
////	printf("\n");
////	qsort(arr, sz, sizeof(arr[0]), cmp_int);
////	for (int i = 0; i < sz; i++)
////	{
////		printf("%d ", arr[i]);
////	}
////}
//
//struct Stu
//{
//	char name[100];//名字
//	int age;//年龄
////};
////////
//////////int buff(const void* e1, const void* e2)
//////////{//(struct Stu*)强制转换为结构体指针 ->age是指向机结构体的类型
//////////	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
//////////}
////////
////void buff1(const void* e1, const void* e2)
////{
////	return strcmp(((struct Stu*)e1)->name ,((struct Stu*)e2)->name);
////}
////
////void test2()
////{
////	struct Stu s[] = { {"zhangsan",20},{"lisi",35},{"wangwu",16} };
////	int sz = sizeof(s) / sizeof(s[0]);
////	qsort(s, sz, sizeof(s[0]), buff1);
////	
////}
//////
////
////
////冒泡排序 两个相邻的数据 进行比较 一次冒泡排序	 让一个数据来到他最终的位置
////进阶冒泡排序
////让 他可以任意类型排序
//
//void swap(char* e1, char* e2, size_t e3)
//{
//	for (int i = 0; i < e3; i++)
//	{
//		char tmp = *e1;
//		*e1 = *e2;
//		*e2 = tmp;
//		e1++;
//		e2++;
//	}
//}
//
//void bubble_sort(int *besa, size_t sz,size_t size,int (*cmp)(const void* e1, const void* e2)) //参考qsort函数;
//{
//	for (int a = 0; a < sz - 1; a++)//求来回几次
//	{
//		for (int j = 0; j < sz - 1 - a; j++)//一次冒泡排序
//		{
//			if (cmp((char*)besa + j * size, (char*)besa + (j + 1) * size) > 0)//强制转换为char类型 *每个元素的大小
//			{//交换
//				swap((char*)besa + j * size, (char*)besa + (j + 1) * size, size);
//			}
//		}
//	}	
//}
////能够比较 e1 e2指向的元素 并且会返回值
//int cmp_int(const void* e1, const void* e2)//回调函数
//{	//void* 类型是无法直接解引用的 得强制转换类型才能解引用
//	return *(int*)e1 - *(int*)e2;
//}
//
//void test2()
//{
//	int arr[] = { 1,2,5,7,8,9,6,3,4,10 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
//}
//////
//int main()
//{
//	//test();
//	test2();
//
//	return 0;
//}
//
////void* 是一种指针类型
////int main()
////{
////	int a = 10;
////	int* p = &a;
////	char* p1 = &a;
////	void* p2 = &a;
////	void* 是通用指针类型 ,可以接收任意数据类型的地址
////	return 0;
////}

//int main()
//{
//	int b = 'A';
//	for (b = 'A'; b <= 'D'; b++)
//	{
//		if ((b != 'A') + (b == 'C') + (b == 'D') + (b != 'D')==3)//A,B一定成立 C与D是相反的 
//		{
//			printf("凶手是:%C", b);
//			
//		}
//	}
//	return 0;
//}

//int main()
//{
//	int arr[3][4] = { {1,2,3,4},{2,3,4,5},{3,4,5,6} };
//	
//	int a = 0;
//	printf("请输入想查找的数字:");
//	scanf("%d", &a);
//	int b = 0;
//	for (int i = 0; i < 3; i++)
//	{
//		for (int j = 0; j < 4; j++)
//		{
//			if (arr[i][j] == a)
//			{
//				printf("存在这个数字");
//				b = 0;
//				return 0;	
//			}
//			else
//			{
//				b = 1;
//			}
//		}
//	}
//	if (b == 1)
//	{
//		printf("不存在这个数字");
//	}
//}

//int ADD(int x, int y)
//{
//	return x + y;
//}
//int SUM(int x, int y)
//{
//	return x - y;
//}
//int JUM(int x, int y)
//{
//	return x / y;
//}
//int NUM(int x, int y)
//{
//	return x * y;
//}
//
//void menu()
//{
//	printf("**************\n");
//	printf("****1.加法****\n");
//	printf("****2.减法****\n");
//	printf("****3.乘法****\n");
//	printf("****4.除法****\n");
//	printf("****0.退出****\n");
//	printf("**************\n");
//}
//
//void cacl(int (*p)(int x, int y))
//{
//	int x, y;
//	printf("请输入2个数字:");
//	scanf("%d %d",&x,&y );
//	int ret =	p(x, y);
//	printf("%d\n", ret);
//}
//
//int main()
//{
//	//函数指针数组 - 存放函数指针的数组
//	int (*Arr[])(int, int) = { 0,ADD,SUM,NUM,JUM };
//	int a = 0;
//
//	do
//	{
//		menu();
//		printf("请选择:");
//		scanf("%d", &a);
//		switch (a)
//		{
//		case 1:
//			cacl(ADD);
//			break;
//		case 2:
//			cacl(SUM);
//			break;
//		case 3:
//			cacl(NUM);
//			break;
//		case 4:
//			cacl(JUM);
//			break;
//		case 0:
//			printf("退出游戏");
//			break;
//		default:
//			printf("选择错误，请重新选择\n");
//		}
//		
//	} while (a);
//	return 0;
//}

//int main()
//{
//	//函数指针数组 - 存放函数指针的数组
//	int (*Arr[])(int, int) = { 0,ADD,SUM,NUM,JUM };
//	int a = 0;
//	int x,y;
//	do
//	{
//		menu();
//		printf("请选择:");
//		scanf("%d", &a);
//		if (a >= 1 && a <= 4)
//		{
//			printf("请输入2个数字:");
//			scanf("%d %d", &x, &y);
//			int ret = Arr[a](x, y);
//			printf("%d\n", ret);
//		}
//		else if (a == 0)
//		{
//			printf("退出程序\n");
//			break;
//		}
//		else
//		{
//			printf("选择错误，请重新选择\n");
//		}
//
//	} while (a);
//	return 0;
//}

////typedef 类型重命名
//typedef int(*pz)[6];//pz必须写*旁边 不能写在后面
//
//int main()
//{
//	int arr[6];
//	int(*p)[6] = &arr;
//	 pz pa = &arr;
//	return 0;
//}

////typedef void(*)(int) tyep ;//错误的定义
//typedef void(*tyep)(int);
//
////int main()
////{
////
////
////	//signal 是一个函数名 
////	//下面的代码事情函数的声明
////	//	void(*)(int)是函数指针 返回类型为void
//	void(*signal(int, void(*)(int)))(int);
//	tyep signal(int, tyep);
//	//void(*)(int)signal(int, void(*)(int));这个是错误的代码
//	return 0;
//}

//int main()
//{ //void (*)() -函数指针类型
//  //(void (*)()) -强制类型转换
//  // 0地址放了 (void (*)()) 这个函数的地址
//  //调用 0地址处的函数 ,调用的函数 参数是无参, 返回类型是void
//	(*(void(*)())0)();
//}

//int arr(int x, int y)
//{
//	return x + y;
//}
//
//int main()
//{
//	int (*p)(int, int) = &arr;//p 是函数指针变量 (*p)()中的()必须要把类型写上
//	int r = (*p)(3, 5);	//*可以不写
//	printf("%d", r);
//	
//	return 0;
//}

//void test(int (*arr)[5], int r, int c)
//{
//	for (int i = 0; i < r; i++)
//	{
//		//*(arr+i)==arr[i]; //等价的
//		for (int j = 0; j < c; j++)
//		{
//			printf("%d", *(*(arr + i) + j));
//			//printf("%d", arr[i][j]);
//		}
//		printf("\n");
//	}
//}
//															
//int main()
//	{
//		int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
//		test(arr, 3, 5);
//		//二维数组传参的本质是 把首元素的地址，也就是第一行数组的地址 传过去
//		return 0;
//	}

//int main()
//{
//	int arr[10];
//	int(*p)[10]=&arr;//数组指针 必须要把指针()起来
//	int* p[10];//指针数组
//	char* ch[8];
//	char* (*p2)[8] = &ch;
//	return 0;
//}

//int main()
//{
//	char str1[] = "hello bit.";
//	char str2[] = "hello bit.";
//	const char* str3 = "hello bit.";//常量字符串是不能被修改的 
//	const char* str4 = "hello bit.";//既然不能被修挂 那么没必要存2份
//	if (str1 == str2)
//		printf("str1 and str2 are same\n");
//	else//即使内容一样 但是所在的空间不一样 所以首元素地址也不一样
//		printf("str1 and str2 are not same\n");
//
//	if (str3 == str4)
//		printf("str3 and str4 are same\n");
//	else
//		printf("str3 and str4 are not same\n");
//
//	return 0;
//}

//int main()
//{
//	char ch = 'a';
//	char* p = &ch;// p 就是字符指针变量
//	//字符指针变量是用来存放地址的
//	const char* pc = "abcdef";//不是将abcdef\0放到指针变量pc中
//	//"abcdef"是常量字符串 不能修改
//	//而是把首字符的地址存放在 pc里;
//	//表达式都有2个属性：值属性、类型属性
//	return 0;
//}

//int main()
//{
//	int arr[] = { 1,2,3,4 };
//	int arr1[] = {5,6,7,8,};
//	int arr2[] = {9,10,11,12};
//	int* p[3] = {arr,arr1,arr2};
//	//数组模拟 二维数组
//	for (int i = 0; i < 4; i++)
//	{
//		for (int j = 0; j < 4; j++)
//		{
//			printf("%d ", p[i][j]);
//			//p[i]== *(p+i);
//			//p[i][j]== *(*(p+i)+j);
//		}
//		printf("\n");
//	}
//	return 0;
//}

//int main()
//{
//	int a = 10;
//	int* p = &a;//p是一级指针
//	//a是整形变量有自己的地址
//	//p是指针变量也有自己的地址
//	int** pp = &p;
//	//int *表示为int类型的指针  *pp表示为指针变量 pp是二级指针
//	int*** ppp = &pp;//三级指针
//
// 	return 0;
//}

//int ADD(int* p, int sz)
//{
//	assert(arr);//控制 指针 使其不变成野指针；
//	int a = 0;//设置左下标
//	int b = sz - 1;//设置右下标
//	while (a < b)
//	{
//		判断偶数在奇数前面
//		while (a < b)
//		{//找到在奇数前的偶数
//			if (p[a] % 2 == 0)
//			{
//				break;
//			}
//			a++;
//		}
//		while (a < b)
//		{//找到在偶数后面的奇数
//			if (p[b] % 2 != 0)
//			{
//				break;
//			}
//			b--;
//		}
//		if (a < b)
//		{
//			交换
//			int tmp = p[a];
//			p[a] = p[b];
//			p[b] = tmp;
//		}
//	}
//}
//
//int main()
//{
//	int arr[] = {1,2,3,4,5,6,7,8};
//	
//		int sz = sizeof(arr) / sizeof(arr[0]);
//		ADD(arr, sz);
//
//		for (int a = 0; a < sz; a++)
//		{
//			printf("%d ", arr[a]);
//		}
//	return 0;
//}

//void ADD(int arr[], int sz)
//{
//	for (int i = 0; i < sz-1; i++)
//	{
//		for (int j = 0; j < sz - 1 - i; j++)
//		{
//			if (arr[j] > arr[j+1])
//			{
//				int tmp = arr[j];
//				arr[j] = arr[j + 1];
//				arr[j + 1] = tmp;
//			}
//		}
//		
//	}
//	for (int a = 0; a < sz; a++)
//	{
//		printf("%d ", arr[a]);
//	}
//}
//
//int main()
//{
//	int arr[] = { 1,5,4,9,8,4,7,6 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	 ADD(arr, sz);
//	
//	return 0;
//}

//int print(int arr[],int sz)
//{
//	int* p = arr;
//	for (int i = 0; i < sz; i++)
//	{
//		printf("%d", *(p + i));
//	}
//}
//
//int main()
//{
//	int arr[] = { 1,2,3,4,5,6,7,8,9 };
//	int sz =sizeof(arr)/sizeof(arr[0]);
//	print(arr,sz);
//	return 0;
//}

//int main()
//{
//	char arr[10000];
//	gets(arr);
//	for (int i = strlen(arr)-1; i >= 0; i--)
//	{
//		printf("%c", arr[i]);
//	}
//}

//int ADD(char* arr, char* s1, int sz, int k)
//{
//	for (int i = 0; i < k; i++)
//	{
//		char tmp = arr[0];//把第一个元素提出来
//		int j = 0;
//		for (j = 0; j < sz - 1; j++)
//		{
//			arr[j] = arr[j + 1];//交换
//		}
//		arr[j] = tmp;//吧第一个元素提到最后一个
//	}
//	if (arr == s1)
//	{
//		return 1;
//	}
//	else
//	{
//		return 0;
//	}
//}
//
//int main()
//{
//	char arr[] = { "ABCD" };
//	char s1[] = {"BCDA"};
//	int sz = strlen(arr);
//	int k = 0;
//	scanf("%d", &k);//左旋次数
//	int a = ADD(arr, s1, sz,k);
//	printf("%d", a);
//	return 0;
//}

//int ADD(char * p)
//{
//	int* a = p;
//
//	while (*p!= '\0')
//	{
//		p++;
//	}
//	return p-a;
//}
//
//int main()
//{
//	char arr[] = {"abcdef"};//strlen 只能算字符不能算 数字
//	//int sz = strlen(arr);
//	int a = ADD(arr);
//	printf("%zd", a);
//	return 0;
//}

//int main()
//{
//	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//	printf("%p\n", &arr[0]);
//	printf("%p\n", &arr[0+1]);//int 类型所以增加4个字节
//
//	printf("%p\n", arr);
//	printf("%p\n", arr+1);//int 类型所以增加4个字节
//
//	printf("%p\n", &arr);
//	printf("%p\n", &arr+1);//增加40个字节
//	return 0;
//}

//int main()
//{
//	int a = 0;
//	int* p = NULL;
//	
//	assert(p != NULL);// assert 类似于 if 但是如果他的表达式不成立 则会报错
//	//#define NDEBUG  可以控制 assert的开关
//	return 0;
//}

//int main()
//{
//	//指针和指针相减 得到的是指针元素之间的个数
//	int arr[10] = { 0 };
//	int res = &arr[9] - &arr[0];
//	printf("%d", res);
//	return 0;
//}

////int main()
////{
////	char arr[] = { "abcdef" };
////	printf("%s\n", arr);
////	char* p = &arr[0];
////	while (*p != '\0')
////	{
////		printf("%c ", *p);
////		p++;
////	}
////	return 0;
////}

////const 修饰指针
////const 放在*左边
////  限制的是指针指向的内容：不能通过指针来修改指向的内容
////const 放在*右边
////	限制的是指针变量本身：不能修改指针变量的指向
//
//int main()
//{   //const 修饰变量,使这个变量无法改变
//	 int a = 100;
//	int n = 200;
//	//int* p = &a;
//	//const int* p = &a;
//	int* const p = &a;
//	*p = 0;
//	p = &n;
//	printf("%d", a);
//
//	return 0;
//}

//int main()
//{
//	int a = 10;//创建变量的本质是：在内存上开辟空间
//	//向内存中 申请4个字节的空间
//	//10 - a
//	//0000 0000 0000 0000 0000 0000 0000 1010
//	//0x 00 00 0a
//	//&a;  &:取地址符号
//	//对于取地址来说 我们拿到的a是所占4个字节的第一个字节的地址(较小的那个地址)
//	//int* prt = &a; //prt 叫指针变量
//	// 指针 == 地址 ==编号
//	
//	int* p = &a;
//	*p = 0;//*是解引用操作符/间接访问操作符
//	//*p的意思是通过p中存放的地址 找到地址所指向的空间 *p 就是 a
//	return 0;
//}